﻿using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using System.Linq;
using System.Data.Linq;
using System.Linq.Dynamic;
using System.Configuration;
using Hxsoft.AppV1;

namespace Hxsoft.AppV1.Module
{
	/// <summary>
	/// 文章的标题类型。
	/// </summary>
	public enum ArticleTitleType
	{
		/// <summary>
		/// 短标题。
		/// </summary>
		ShortTitle,
		/// <summary>
		/// 中标题。
		/// </summary>
		MiddleTitle,
		/// <summary>
		/// 长标题。
		/// </summary>
		Title
	}

	/// <summary>
	/// 文章统计方式
	/// </summary>
	public enum StatisticsClass
	{
		/// <summary>
		/// 按照站点方式统计
		/// </summary>
		StatisticsWithSite = 1,
		/// <summary>
		/// 按照用户名统计
		/// </summary>
		StatisticsWithUser
	}

	/// <summary>
	/// 文章实体。
	/// </summary>
	public partial class Article : ICreator
	{
		/// <summary>
		/// 根据分页标识符分隔文章内容到一个列表中。
		/// </summary>
		/// <returns>分隔后的文章内容列表。</returns>
		public List<string> SplitContent()
		{
			string content = ArtContent;
			if (content == null) content = "";

			List<string> contents = new List<string>();
			Regex re = new Regex(@"<div style=""page-break-after:\s*always;?\s*""><span style=""DISPLAY:\s*none;?\s*"">(.*?)</span></div>", RegexOptions.IgnoreCase);
			MatchCollection mc = re.Matches(content);
			int p = 0;
			foreach (Match m in mc)
			{
				contents.Add(content.Substring(p, m.Index - p));
				p = m.Index + m.Length;
			}

			contents.Add(content.Substring(p));

			return contents;
		}
	}



	/// <summary>
	/// Articles 类。
	/// </summary>
	public static partial class Articles
	{
		/// <summary>
		/// 文章浏览量值
		/// </summary>
		private static string ReadCount = StringExtensions.GetEffectiveValueOrDefault(ConfigurationManager.AppSettings["ReadCount"], "1");

		/// <summary>
		/// 文章的信息类别。
		/// </summary>
		public const string INFO_TYPE = "Article";

		#region GetItem
		/// <summary>
		/// 根据标识获取指定的文章。
		/// </summary>
		/// <param name="o">文章集合。</param>
		/// <param name="articleId">获取的文章标识 ArticleId。</param>
		/// <returns>获取的信息项。</returns>
		public static Article GetItem(this System.Data.Linq.Table<Article> o, int articleId)
		{
			return o.SingleOrDefault(p => p.ArticleId == articleId);
		}

		public static Article GetItem(int articleId)
		{
			GenericModuleDataContext dc = new GenericModuleDataContext();
			dc.ObjectTrackingEnabled = false;
			return dc.Articles.GetItem(articleId);
		}



		/// <summary>
		/// 根据标识获取指定的文章。
		/// </summary>
		/// <param name="o">文章集合。</param>
		/// <param name="articleCode">获取的文章标识 articleCode。</param>
		/// <returns>获取的信息项。</returns>
		public static Article GetItem(GenericModuleDataContext dc, int siteId, string articleCode)
		{
			var q = from p in dc.Articles
					from p2 in dc.ModuleArticles
					from p3 in dc.Modules
					where p.ArticleId == p2.ArticleId && p2.ModuleId == p3.ModuleId && p3.SiteId == siteId && p.ArticleCode == articleCode
					select p;
			return q.FirstOrDefault();
		}

		/// <summary>
		/// 根据文章代码获取指定的文章。
		/// </summary>
		/// <param name="articleCode">文章的代码。</param>
		/// <returns>获取的信息项。</returns>
		public static Article GetItem(int siteId, string articleCode)
		{
			GenericModuleDataContext dc = new GenericModuleDataContext();
			dc.ObjectTrackingEnabled = false;
			return GetItem(dc, siteId, articleCode);
		}
		#endregion



		#region GetNext
		/// <summary>
		/// 获取指定时间的邻近文章。
		/// </summary>
		/// <param name="dc">文章集合。</param>
		/// <param name="moduleId">文章所处的模块。</param>
		/// <param name="releaseDate">指定的时间。</param>
		/// <param name="offset">获取的文章偏向及数量，负数为之前的文章，正数为之后的文章。如：-10为指定文章的前10条文章。</param>
		/// <returns>指定时间的邻近文章。</returns>
		public static List<Article> GetAdjacentArticles(GenericModuleDataContext dc, int moduleId, DateTime releaseDate, int offset)
		{
			if(offset == 0)
				return new List<Article>();

			if(offset < 0)
				return(from p in dc.Articles
					from p2 in dc.ModuleArticles
					   where p.ArticleId == p2.ArticleId && p2.ModuleId == moduleId && p.IsEffective == true && p2.IsEffective == true && p.ReleaseDate < releaseDate
					orderby p2.ReleaseDate descending, p.ReleaseDate descending
					select p).Take(-offset).ToList();
			return (from p in dc.Articles
					from p2 in dc.ModuleArticles
					where p.ArticleId == p2.ArticleId && p2.ModuleId == moduleId && p.IsEffective == true && p2.IsEffective == true && p.ReleaseDate > releaseDate
					orderby p2.ReleaseDate, p.ReleaseDate
					select p).Take(offset).ToList();
		}

		/// <summary>
		/// 获取指定时间的邻近文章。
		/// </summary>
		/// <param name="moduleId">文章所处的模块。</param>
		/// <param name="releaseDate">指定的时间。</param>
		/// <param name="offset">获取的文章偏向及数量，负数为之前的文章，正数为之后的文章。如：-10为指定文章的前10条文章。</param>
		/// <returns>指定时间的邻近文章。</returns>
		public static List<Article> GetAdjacentArticles(int moduleId, DateTime releaseDate, int offset)
		{
			GenericModuleDataContext dc = new GenericModuleDataContext();
			dc.ObjectTrackingEnabled = false;
			return GetAdjacentArticles(dc, moduleId, releaseDate, offset);
		}

		/// <summary>
		/// 获取指定时间的下一篇文章。
		/// </summary>
		/// <param name="moduleId">文章所处的模块。</param>
		/// <param name="releaseDate">指定的时间。</param>
		/// <returns>指定时间的下一篇文章。</returns>
		public static Article GetNextArticle(int moduleId, DateTime releaseDate)
		{
			List<Article> articles = GetAdjacentArticles(moduleId, releaseDate, 1);
			if (articles.Count > 0)
				return articles[0];
			return null;
		}

		/// <summary>
		/// 获取指定时间的上一篇文章。
		/// </summary>
		/// <param name="moduleId">文章所处的模块。</param>
		/// <param name="releaseDate">指定的时间。</param>
		/// <returns>指定时间的上一篇文章。</returns>
		public static Article GetPrevArticle(int moduleId, DateTime releaseDate)
		{
			List<Article> articles = GetAdjacentArticles(moduleId, releaseDate, -1);
			if (articles.Count > 0)
				return articles[0];
			return null;
		}
		#endregion



		#region Exists
		/// <summary>
		/// 验证指定的文章是否已经存在。
		/// </summary>
		/// <param name="o">文章集合。</param>
		/// <param name="articleId">验证的文章标识 ArticleId。</param>
		/// <returns>布尔值表示指定的文章是否已经存在。</returns>
		public static bool Exists(this System.Data.Linq.Table<Article> o, int articleId)
		{
			return o.Any(p => p.ArticleId == articleId);
		}
		#endregion
	}



	/// <summary>
	/// Articles 类操作部分。
	/// </summary>
	public static partial class Articles
	{
		#region Read
		/// <summary>
		/// 阅读文章。
		/// </summary>
		/// <param name="articleId">阅读文章的标识。</param>
		/// <returns>阅读的文章。</returns>
		public static Article Read(int articleId)
		{
			GenericModuleDataContext dc = new GenericModuleDataContext();
			
			Article article = dc.Articles.GetItem(articleId);
			if (article == null || article.IsEffective == false) return null;
			article.ReadCount += int.Parse(ReadCount);

			try
			{
				dc.SubmitChanges(ConflictMode.ContinueOnConflict);
			}
			catch (ChangeConflictException e)
			{
				foreach (ObjectChangeConflict occ in dc.ChangeConflicts)
				{
					occ.Resolve(RefreshMode.KeepCurrentValues);
				}
			}

			return article;
		}

		/// <summary>
		/// 读取模块最后发布的文章。
		/// </summary>
		/// <param name="moduleId">模块的ID。</param>
		/// <returns>阅读的文章。</returns>
		public static Article ReadModuleTopArticle(int moduleId)
		{
			GenericModuleDataContext dc = new GenericModuleDataContext();
			var q = from p in dc.Articles
					from p1 in dc.ModuleArticles
					where p.ArticleId == p1.ArticleId && p1.ModuleId == moduleId && p.IsEffective == true && p1.IsEffective == true
					orderby p1.ArticleOrder descending,p.ReleaseDate descending
					select p;

			Article article = q.FirstOrDefault();
			if (article == null) return new Article();
			article.ReadCount += int.Parse(ReadCount);

			try
			{
				dc.SubmitChanges(ConflictMode.ContinueOnConflict);
			}
			catch (ChangeConflictException e)
			{
				foreach (ObjectChangeConflict occ in dc.ChangeConflicts)
				{
					occ.Resolve(RefreshMode.KeepCurrentValues);
				}
			}

			return article;
		}

		/// <summary>
		/// 阅读文章。
		/// </summary>
		/// <param name="siteId">阅读文章所属的站点。</param>
		/// <param name="articleCode">阅读文章的代码。</param>
		/// <returns>阅读的文章。</returns>
		public static Article Read(int siteId, string articleCode)
		{
			GenericModuleDataContext dc = new GenericModuleDataContext();

			Article article = GetItem(dc, siteId, articleCode);
			if (article == null || article.IsEffective ==  false) return null;
			article.ReadCount += int.Parse(ReadCount);

			try
			{
				dc.SubmitChanges(ConflictMode.ContinueOnConflict);
			}
			catch (ChangeConflictException e)
			{
				foreach (ObjectChangeConflict occ in dc.ChangeConflicts)
				{
					occ.Resolve(RefreshMode.KeepCurrentValues);
				}
			}

			return article;
		}
		#endregion

        #region ReadForReadCount
        /// <summary>
        /// 阅读文章。
        /// </summary>
        /// <param name="articleId">阅读文章的标识。</param>
        /// <returns>阅读的文章。</returns>
        public static Article Read(int articleId,bool isAdd)
        {
            GenericModuleDataContext dc = new GenericModuleDataContext();

            Article article = dc.Articles.GetItem(articleId);
            if (article == null || article.IsEffective == false) return null;
            if (isAdd)
            {
				article.ReadCount += int.Parse(ReadCount);
            }

            try
            {
                dc.SubmitChanges(ConflictMode.ContinueOnConflict);
            }
            catch (ChangeConflictException e)
            {
                foreach (ObjectChangeConflict occ in dc.ChangeConflicts)
                {
                    occ.Resolve(RefreshMode.KeepCurrentValues);
                }
            }

            return article;
        }

        /// <summary>
        /// 读取模块最后发布的文章。
        /// </summary>
        /// <param name="moduleId">模块的ID。</param>
        /// <returns>阅读的文章。</returns>
        public static Article ReadModuleTopArticle(int moduleId,bool isAdd)
        {
            GenericModuleDataContext dc = new GenericModuleDataContext();
            var q = from p in dc.Articles
                    from p1 in dc.ModuleArticles
                    where p.ArticleId == p1.ArticleId && p1.ModuleId == moduleId && p.IsEffective == true && p1.IsEffective == true
                    orderby p1.ArticleOrder descending, p.ReleaseDate descending
                    select p;

            Article article = q.FirstOrDefault();
            if (article == null) return new Article();
            if (isAdd)
            {
				article.ReadCount += int.Parse(ReadCount);
            }

            try
            {
                dc.SubmitChanges(ConflictMode.ContinueOnConflict);
            }
            catch (ChangeConflictException e)
            {
                foreach (ObjectChangeConflict occ in dc.ChangeConflicts)
                {
                    occ.Resolve(RefreshMode.KeepCurrentValues);
                }
            }

            return article;
        }

        /// <summary>
        /// 阅读文章。
        /// </summary>
        /// <param name="siteId">阅读文章所属的站点。</param>
        /// <param name="articleCode">阅读文章的代码。</param>
        /// <returns>阅读的文章。</returns>
        public static Article Read(int siteId, string articleCode,bool isAdd)
        {
            GenericModuleDataContext dc = new GenericModuleDataContext();

            Article article = GetItem(dc, siteId, articleCode);
            if (article == null || article.IsEffective == false) return null;
            if (isAdd)
            {
				article.ReadCount += int.Parse(ReadCount);
            }

            try
            {
                dc.SubmitChanges(ConflictMode.ContinueOnConflict);
            }
            catch (ChangeConflictException e)
            {
                foreach (ObjectChangeConflict occ in dc.ChangeConflicts)
                {
                    occ.Resolve(RefreshMode.KeepCurrentValues);
                }
            }

            return article;
        }
        #endregion

		#region Insert
		/// <summary>
		/// 添加文章。
		/// </summary>
		/// <param name="insertedArticle">添加的文章。</param>
		/// <returns>添加的文章。</returns>
		public static Article Insert(Article insertedArticle)
		{
			GenericModuleDataContext dc = new GenericModuleDataContext();

			Article article = insertedArticle.ToNewEntity<Article>();
			article.ReadCount = 0;
			article.IsEffective = false;
			article.CreatorId = Users.CurrentUserId;
			article.CreationDate = DateTime.Now;
            article.ArticleCount = BuildArticleCount(article.ArtContent);

			GetInsertRight(dc, article, true);	// 权限验证

			dc.Articles.InsertOnSubmit(article);
			dc.SubmitChanges();

			// 持久化资源
			InfoItems.SetPersistent(dc, article.GlobalId, true);

			// 记录日志
			Logs.Insert(dc, ResourceId, (int)PermissionCode.Insert, INFO_TYPE, article.ArticleId.ToString(), PermissionCode.Insert.ToString(), article.Title);

			// 返回只读数据
			return insertedArticle.FillByEntity(article);
		}
		#endregion



		#region Update
		/// <summary>
		/// 更新时排除的列。
		/// </summary>
		private static readonly HashSet<string> _updatedExcludeColumns = typeof(Article).GetEntityColumnNames(new string[] {
				"ArticleId",
				"ReadCount",
				"IsEffective",
				"CreationDate",
				"CreatorId",
				"GlobalId",
				"ReadGrade"
			}, true);

		/// <summary>
		/// 修改文章。
		/// </summary>
		/// <param name="updatedArticle">修改的文章。</param>
		/// <returns>修改的文章。</returns>
		public static Article Update(Article updatedArticle)
		{
			GenericModuleDataContext dc = new GenericModuleDataContext();

			Article article = dc.Articles.GetItem(updatedArticle.ArticleId);
			if (article == null)
				throw new ObjectNotExistsException(Res.Operation_ObjectNotExists);

			updatedArticle.ArticleCount = BuildArticleCount(updatedArticle.ArtContent);

			GetUpdateRight(dc, article, true);	// 权限验证

			article.FillByEntity(updatedArticle, EntityColumnsSetType.Exclude, _updatedExcludeColumns);

			try
			{
				dc.SubmitChanges(ConflictMode.ContinueOnConflict);
			}
			catch (ChangeConflictException e)
			{
				foreach (ObjectChangeConflict occ in dc.ChangeConflicts)
				{
					occ.Resolve(RefreshMode.KeepCurrentValues);
				}
			}

			// 持久化资源
			InfoItems.SetPersistent(dc, article.GlobalId, true);

			// 记录日志
			Logs.Insert(dc, ResourceId, (int)PermissionCode.Update, INFO_TYPE, article.ArticleId.ToString(), PermissionCode.Update.ToString(), article.Title);

			// 返回只读数据
			return updatedArticle.FillByEntity(article);
		}

		/// <summary>
		/// 更新相头链接。
		/// </summary>
		/// <param name="articleId">文章标识。</param>
		/// <param name="link">相关链接内容。</param>
		public static string UpdateLink(int articleId, string link)
		{
			GenericModuleDataContext dc = new GenericModuleDataContext();

			Article article = dc.Articles.GetItem(articleId);
			if (article == null)
				return link;

			article.Link = link;

			try
			{
				dc.SubmitChanges(ConflictMode.ContinueOnConflict);
			}
			catch (ChangeConflictException e)
			{
				foreach (ObjectChangeConflict occ in dc.ChangeConflicts)
				{
					occ.Resolve(RefreshMode.KeepCurrentValues);
				}
			}

			return link;
		}
		#endregion


        #region 文章字数统计
		/// <summary>
		/// 文章字数统计
		/// </summary>
		/// <param name="artConntent"></param>
		/// <returns></returns>
        internal static int?  BuildArticleCount(string artConntent)
        {
            if (String.IsNullOrEmpty(artConntent)) return 0;

			//清除html标签 和 html转义字符
			artConntent = artConntent.FilterHtmlTag();            
			artConntent = artConntent.Replace("\n", "").Replace("&nbsp;", "");
			artConntent = artConntent.Replace("&ldquo;", "'").Replace("&rdquo;", "'").Replace("&amp;", "&");
			artConntent = artConntent.Replace("&laquo;", "«").Replace("&raquo;", "»").Replace("&lt;&lt;", "《").Replace("&gt;&gt;", "》");
            artConntent = artConntent.Replace("&lt;", "<").Replace("&gt;", ">").Replace(" ", "").Trim();

            if (String.IsNullOrEmpty(artConntent)) return 0;

            return artConntent.Length;
        } 
        #endregion



        #region Setting
        /// <summary>
		/// 设置列。
		/// </summary>
		private static readonly HashSet<string> _settedColumns = typeof(Article).GetEntityColumnNames(new string[] {
				"ReadCount",
				"IsEffective",
				"ReadGrade"
			}, true);

		/// <summary>
		/// 设置文章。
		/// </summary>
		/// <param name="settedArticle">设置的文章。</param>
		/// <returns>设置的文章。</returns>
		public static Article Setting(Article settedArticle)
		{
			GenericModuleDataContext dc = new GenericModuleDataContext();

			Article article = dc.Articles.GetItem(settedArticle.ArticleId);
			if (article == null)
				throw new ObjectNotExistsException(Res.Operation_ObjectNotExists);

			GetSettingRight(dc, article, true);	// 权限验证

			article.FillByEntity(settedArticle, _settedColumns);

			try
			{
				dc.SubmitChanges(ConflictMode.ContinueOnConflict);
			}
			catch (ChangeConflictException e)
			{
				foreach (ObjectChangeConflict occ in dc.ChangeConflicts)
				{
					occ.Resolve(RefreshMode.KeepCurrentValues);
				}
			}

			// 记录日志
			Logs.Insert(dc, ResourceId, (int)PermissionCode.Setting, INFO_TYPE, article.ArticleId.ToString(), PermissionCode.Setting.ToString(), article.Title);

			// 返回只读数据
			return settedArticle.FillByEntity(article);
		}
		#endregion



		#region SetEffectiveState
		/// <summary>
		/// 设置信息的有效状态。
		/// </summary>
		/// <param name="articleId">设置的信息标识。</param>
		public static void SetEffectiveState(int articleId)
		{
			GenericModuleDataContext dc = new GenericModuleDataContext();

			Article article = dc.Articles.GetItem(articleId);
			if (article == null)
				throw new ObjectNotExistsException(Res.Operation_ObjectNotExists);

			GetSetEffectiveStateRight(dc, article, true);	// 权限验证

			article.IsEffective = !article.IsEffective;
			try
			{
				dc.SubmitChanges(ConflictMode.ContinueOnConflict);
			}
			catch (ChangeConflictException e)
			{
				foreach (ObjectChangeConflict occ in dc.ChangeConflicts)
				{
					occ.Resolve(RefreshMode.KeepCurrentValues);
				}
			}

			// 记录日志
			Logs.Insert(dc, ResourceId, (int)PermissionCode.Setting, INFO_TYPE, article.ArticleId.ToString(), PermissionCode.Setting.ToString() + "/EffectiveState", article.Title);
		}

		/// <summary>
		/// 设置信息的有效状态。
		/// </summary>
		/// <param name="articleId">设置的信息标识。</param>
		/// <param name="state">设置的状态。</param>
		public static void SetEffectiveState(int articleId, bool state)
		{
			GenericModuleDataContext dc = new GenericModuleDataContext();

			Article article = dc.Articles.GetItem(articleId);
			if (article == null)
				throw new ObjectNotExistsException(Res.Operation_ObjectNotExists);

			GetSetEffectiveStateRight(dc, article, true);	// 权限验证

			if (article.IsEffective == state)
				return;

			article.IsEffective = state;
			try
			{
				dc.SubmitChanges(ConflictMode.ContinueOnConflict);
			}
			catch (ChangeConflictException e)
			{
				foreach (ObjectChangeConflict occ in dc.ChangeConflicts)
				{
					occ.Resolve(RefreshMode.KeepCurrentValues);
				}
			}

			// 记录日志
			Logs.Insert(dc, ResourceId, (int)PermissionCode.Setting, INFO_TYPE, article.ArticleId.ToString(), PermissionCode.Setting.ToString() + "/EffectiveState", article.Title);
		}
		#endregion



		#region Delete
		/// <summary>
		/// 删除文章。
		/// </summary>
		/// <param name="articleId">删除的文章标识 ArticleId。</param>
		public static void Delete(int articleId)
		{
			GenericModuleDataContext dc = new GenericModuleDataContext();

			Article article = dc.Articles.GetItem(articleId);
			if (article == null)
				throw new ObjectNotExistsException(Res.Operation_ObjectNotExists);

			GetDeleteRight(dc, article, true);	// 权限验证

			Delete(dc, article);

			dc.SubmitChanges();

			// 记录日志
			Logs.Insert(dc, ResourceId, (int)PermissionCode.Delete, INFO_TYPE, article.ArticleId.ToString(), PermissionCode.Delete.ToString(), article.Title);
		}

		#region internal Delete
		/// <summary>
		/// 删除相关信息。
		/// </summary>
		/// <param name="dc">数据容器。</param>
		/// <param name="article">删除的文章。</param>
		internal static void Delete(GenericModuleDataContext dc, Article article)
		{
			ModuleArticles.DeleteByParent(dc, article);	// 删除关联数据
			dc.Articles.DeleteOnSubmit(article);

			// 删除资源
			InfoItem infoItem = dc.InfoItems.GetItem(article.GlobalId);
			if (infoItem != null)
				InfoItems.Delete(dc, infoItem);
		}
		#endregion
		#endregion



		#region RegisterCommentInfoType
		/// <summary>
		/// 评论的信息类别。
		/// </summary>
		public static readonly Dictionary CommentInfoType = RegisterCommentInfoType();

		/// <summary>
		/// 注册评论信息类别。
		/// </summary>
		/// <returns>注册的评论信息类别。</returns>
		internal static Dictionary RegisterCommentInfoType()
		{
			DicClass dicClass = Comments.CommentDicClass;

			Dictionary info = new Dictionary();
			info.ClassId = dicClass.ClassId;
			info.DicId = 1;
			info.DicCode = INFO_TYPE;
			info.Value = INFO_TYPE;
			info.Name = "文章";

			return Dictionaries.Register(info);
		}
		#endregion
	}



	/// <summary>
	/// Articles 类对应操作权限部分。
	/// </summary>
	public static partial class Articles
	{
		#region GetInsertRight
		/// <summary>
		/// 获取当前用户是否有添加文章的权限。
		/// </summary>
		/// <param name="dc">数据容器。</param>
		/// <param name="article">添加的文章对象。</param>
		/// <param name="triggerException">当未通过权限验证的时候是否引发异常。</param>
		/// <returns>布尔值表示当前用户是否有添加文章的权限。</returns>
		public static bool GetInsertRight(GenericModuleDataContext dc, Article article, bool triggerException)
		{
			string userName = Users.CurrentUserName;
			int permissionCode = (int)PermissionCode.Insert;
			bool b = dc.AccessController.GetUserIsHasPermission<Article>(userName, article, ResourceId, permissionCode);

			if (triggerException && !b)
				throw new PermissionException(userName, article, ResourceId, permissionCode, Res.PermissionExceptionMessage);
			return b;
		}

		/// <summary>
		/// 获取当前用户是否有添加文章的权限。
		/// </summary>
		/// <param name="article">添加的文章对象。</param>
		/// <param name="triggerException">当未通过权限验证的时候是否引发异常。</param>
		/// <returns>布尔值表示当前用户是否有添加文章的权限。</returns>
		public static bool GetInsertRight(Article article, bool triggerException)
		{
			return GetInsertRight(new GenericModuleDataContext(), article, triggerException);
		}

		/// <summary>
		/// 获取当前用户是否有添加文章的权限。
		/// </summary>
		/// <param name="article">添加的文章对象。</param>
		/// <returns>布尔值表示当前用户是否有添加文章的权限。</returns>
		public static bool GetInsertRight(Article article)
		{
			return GetInsertRight(article, false);
		}
		#endregion



		#region GetUpdateRight
		/// <summary>
		/// 获取当前用户是否有更新文章的权限。
		/// </summary>
		/// <param name="dc">数据容器。</param>
		/// <param name="article">更新的文章对象。</param>
		/// <param name="triggerException">当未通过权限验证的时候是否引发异常。</param>
		/// <returns>布尔值表示当前用户是否有更新文章的权限。</returns>
		public static bool GetUpdateRight(GenericModuleDataContext dc, Article article, bool triggerException)
		{
			string userName = Users.CurrentUserName;
			int permissionCode = (int)PermissionCode.Update;
			bool b = dc.AccessController.GetUserIsHasPermission<Article>(userName, article, ResourceId, permissionCode);

			if (triggerException && !b)
				throw new PermissionException(userName, article, ResourceId, permissionCode, Res.PermissionExceptionMessage);
			return b;
		}

		/// <summary>
		/// 获取当前用户是否有更新文章的权限。
		/// </summary>
		/// <param name="article">更新的文章对象。</param>
		/// <param name="triggerException">当未通过权限验证的时候是否引发异常。</param>
		/// <returns>布尔值表示当前用户是否有更新文章的权限。</returns>
		public static bool GetUpdateRight(Article article, bool triggerException)
		{
			return GetUpdateRight(new GenericModuleDataContext(), article, triggerException);
		}

		/// <summary>
		/// 获取当前用户是否有更新文章的权限。
		/// </summary>
		/// <param name="article">更新的文章对象。</param>
		/// <returns>布尔值表示当前用户是否有更新文章的权限。</returns>
		public static bool GetUpdateRight(Article article)
		{
			return GetUpdateRight(article, false);
		}
		#endregion



		#region GetSettingRight
		/// <summary>
		/// 获取当前用户是否有设置文章的权限。
		/// </summary>
		/// <param name="dc">数据容器。</param>
		/// <param name="article">设置的文章对象。</param>
		/// <param name="triggerException">当未通过权限验证的时候是否引发异常。</param>
		/// <returns>布尔值表示当前用户是否有设置文章的权限。</returns>
		public static bool GetSettingRight(GenericModuleDataContext dc, Article article, bool triggerException)
		{
			string userName = Users.CurrentUserName;
			int permissionCode = (int)PermissionCode.Setting;
			bool b = dc.AccessController.GetUserIsHasPermission<Article>(userName, article, ResourceId, permissionCode);

			if (triggerException && !b)
				throw new PermissionException(userName, article, ResourceId, permissionCode, Res.PermissionExceptionMessage);
			return b;
		}

		/// <summary>
		/// 获取当前用户是否有设置文章的权限。
		/// </summary>
		/// <param name="article">设置的文章对象。</param>
		/// <param name="triggerException">当未通过权限验证的时候是否引发异常。</param>
		/// <returns>布尔值表示当前用户是否有设置文章的权限。</returns>
		public static bool GetSettingRight(Article article, bool triggerException)
		{
			return GetSettingRight(new GenericModuleDataContext(), article, triggerException);
		}

		/// <summary>
		/// 获取当前用户是否有设置文章的权限。
		/// </summary>
		/// <param name="article">设置的文章对象。</param>
		/// <returns>布尔值表示当前用户是否有设置文章的权限。</returns>
		public static bool GetSettingRight(Article article)
		{
			return GetSettingRight(article, false);
		}



		/// <summary>
		/// 获取设置信息有效状态的权限。
		/// </summary>
		/// <param name="dc">数据容器。</param>
		/// <param name="article">设置的文章对象。</param>
		/// <param name="triggerException">当未通过权限验证的时候是否引发异常。</param>
		/// <returns>布尔值表示当前用户是否有设置文章的权限。</returns>
		public static bool GetSetEffectiveStateRight(GenericModuleDataContext dc, Article article, bool triggerException)
		{
			return GetSettingRight(dc, article, triggerException);
		}

		/// <summary>
		/// 获取设置信息有效状态的权限。
		/// </summary>
		/// <param name="article">设置的文章对象。</param>
		/// <param name="triggerException">当未通过权限验证的时候是否引发异常。</param>
		/// <returns>布尔值表示当前用户是否有设置文章的权限。</returns>
		public static bool GetSetEffectiveStateRight(Article article, bool triggerException)
		{
			return GetSetEffectiveStateRight(new GenericModuleDataContext(), article, triggerException);
		}

		/// <summary>
		/// 获取设置信息有效状态的权限。
		/// </summary>
		/// <param name="article">设置的文章对象。</param>
		/// <returns>布尔值表示当前用户是否有设置文章的权限。</returns>
		public static bool GetSetEffectiveStateRight(Article article)
		{
			return GetSetEffectiveStateRight(article, false);
		}
		#endregion



		#region GetDeleteRight
		/// <summary>
		/// 获取当前用户是否有删除文章的权限。
		/// </summary>
		/// <param name="dc">数据容器。</param>
		/// <param name="article">删除的文章对象。</param>
		/// <param name="triggerException">当未通过权限验证的时候是否引发异常。</param>
		/// <returns>布尔值表示当前用户是否有删除文章的权限。</returns>
		public static bool GetDeleteRight(GenericModuleDataContext dc, Article article, bool triggerException)
		{
			string userName = Users.CurrentUserName;
			int permissionCode = (int)PermissionCode.Delete;
			bool b = dc.AccessController.GetUserIsHasPermission<Article>(userName, article, ResourceId, permissionCode);

			if (triggerException && !b)
				throw new PermissionException(userName, article, ResourceId, permissionCode, Res.PermissionExceptionMessage);
			return b;
		}

		/// <summary>
		/// 获取当前用户是否有删除文章的权限。
		/// </summary>
		/// <param name="article">删除的文章对象。</param>
		/// <param name="triggerException">当未通过权限验证的时候是否引发异常。</param>
		/// <returns>布尔值表示当前用户是否有删除文章的权限。</returns>
		public static bool GetDeleteRight(Article article, bool triggerException)
		{
			return GetDeleteRight(new GenericModuleDataContext(), article, triggerException);
		}

		/// <summary>
		/// 获取当前用户是否有删除文章的权限。
		/// </summary>
		/// <param name="article">删除的文章对象。</param>
		/// <returns>布尔值表示当前用户是否有删除文章的权限。</returns>
		public static bool GetDeleteRight(Article article)
		{
			return GetDeleteRight(article, false);
		}
		#endregion
	}




	/// <summary>
	/// Articles 类后台管理部分。
	/// </summary>
	public static partial class Articles
	{
		/// <summary>
		/// 文章管理列表实体。
		/// </summary>
		public class ArticleForManageList
		{
			/// <summary>
			/// 文章标识。
			/// </summary>
			public int ArticleId { get; set; }
			/// <summary>
			/// 文章标题。
			/// </summary>
			public string Title { get; set; }
			/// <summary>
			/// 是否有效。
			/// </summary>
			public bool IsEffective { get; set; }
			/// <summary>
			/// 发布日期。
			/// </summary>
			public DateTime ReleaseDate { get; set; }
			/// <summary>
			/// 创建者标识。
			/// </summary>
			public Guid? CreatorId { get; set; }

			private string _creatorName = null;
			/// <summary>
			/// 创建者名。
			/// </summary>
			public string CreatorName
			{
				get { return string.IsNullOrEmpty(_creatorName) ? CreatorId.HasValue ? Users.GetUserName(CreatorId.Value) : null : _creatorName; }
				internal set { _creatorName = value; }
			}

			public string ChannelIds { get; set; }
			public bool IsRecommend { get; set; }
		}

		/// <summary>
		/// 文章统计列表实体
		/// </summary>
		[Serializable]
		public struct ArticleForStatisticsList
		{
			public int ArticleId { get; set; }			
			public int ModuleId { get; set; }
			public string ModuleName { get; set; }
			public string ModuleCode { get; set; }
			public int SiteId { get; set; }			
			public DateTime ReleaseDate { get; set; }
			public Guid? CreatorID { get; set; }			
			public int? ArticleCount { get; set; }
			public string ChannelIds { get; set; }
			public bool IsRecommend { get; set; }
		}


		/// <summary>
		/// 获取管理列表的权限。
		/// </summary>
		/// <returns>是否拥有管理列表的权限。</returns>
		public static bool GetManageListRight()
		{
			GenericModuleDataContext dc = new GenericModuleDataContext();
			return dc.AccessController.GetUserIsHasPermission<object>(Users.CurrentUserName, null, Articles.ResourceId, (int)Articles.PermissionCode.Insert);
		}

		/// <summary>
		/// 获取文章统计权限
		/// </summary>
		/// <returns></returns>
		public static bool GetStatisticsListRight()
		{
			GenericModuleDataContext dc = new GenericModuleDataContext();
			return dc.AccessController.GetUserIsHasPermission<object>(Users.CurrentUserName, null, Articles.ResourceId, (int)Articles.PermissionCode.Statistics);
		}
		/// <summary>
		/// 获取文章统计权限
		/// </summary>
		/// <param name="userName"></param>
		/// <returns></returns>

		public static bool GetStatisticsListRight(string userName)
		{
			GenericModuleDataContext dc = new GenericModuleDataContext();
			return dc.AccessController.GetUserIsHasPermission<object>(userName, null, Articles.ResourceId, (int)Articles.PermissionCode.Statistics);
		}


		/// <summary>
		/// 文章统计查询
		/// </summary>
		/// <param name="dc"></param>
		/// <param name="statistics"></param>
		/// <param name="siteId"></param>
		/// <param name="userId"></param>
		/// <param name="startTime"></param>
		/// <param name="endTime"></param>
		/// <param name="keyword"></param>
		/// <returns></returns>
		private static IQueryable<ArticleForStatisticsList> ArticleStatisticsQuery(GenericModuleDataContext dc,int? statistics, int? siteId, Guid? userId, DateTime? startTime, DateTime? endTime, string keyword)
		{
			var q = from p in dc.ArticleInfos
					where p.IsEffective && p.IsRelease
					orderby p.ReleaseDate descending
					select new ArticleForStatisticsList
					{
						ArticleId = p.ArticleID,												
						ModuleId = p.ModuleID,
						ModuleName = p.ModuleCaption,						
						SiteId = p.SiteID,						
						ReleaseDate = p.ReleaseDate,
						CreatorID = p.CreatorID,
						ArticleCount=p.ArticleCount
					};
			if (siteId.HasValue)
				q = q.Where(p => p.SiteId == siteId.Value);
			if (userId.HasValue)
				q = q.Where(p => p.CreatorID == userId);
			if (startTime.HasValue)
				q = q.Where(p => p.ReleaseDate >= startTime.Value);
			if (endTime.HasValue)
				q = q.Where(p => p.ReleaseDate < endTime.Value.AddDays(1));

			if (!string.IsNullOrEmpty(keyword))
				q = q.Where(p => p.ModuleName.Contains(keyword));

			if (statistics.HasValue)
			{
				switch (statistics.Value)
				{
					case (int)StatisticsClass.StatisticsWithSite:
						var q2 = q.Select(p => new ArticleForStatisticsList
						{
							SiteId = p.SiteId
						}).Distinct().OrderBy(p=>p.SiteId);
						return q2;

					case (int)StatisticsClass.StatisticsWithUser:
						var q3 = q.Select(p => new ArticleForStatisticsList
						{
							CreatorID = p.CreatorID
						}).Distinct();
						return q3;
				}
			}
			return q;
		}

		/// <summary>
		/// 获取文章统计分页列表
		/// </summary>
		/// <param name="statistics"></param>
		/// <param name="siteId"></param>
		/// <param name="userId"></param>
		/// <param name="startTime"></param>
		/// <param name="endTime"></param>
		/// <param name="keyword"></param>
		/// <param name="pageSize"></param>
		/// <param name="currentPage"></param>
		/// <returns></returns>
		public static PaginationInfo<List<ArticleForStatisticsList>> GetPaginationArticleStatisticsList(int? statistics, int? siteId, Guid? userId, DateTime? startTime, DateTime? endTime, string keyword, int pageSize, int currentPage)
		{
			GenericModuleDataContext dc = new GenericModuleDataContext();
			dc.ObjectTrackingEnabled = false;

			IQueryable<ArticleForStatisticsList> q = ArticleStatisticsQuery(dc, statistics, siteId, userId, startTime, endTime, keyword);

			PaginationInfo<List<ArticleForStatisticsList>> pageInfo = new PaginationInfo<List<ArticleForStatisticsList>>();
			pageInfo.PageSize = pageSize;
			pageInfo.CurrentPage = currentPage;
			pageInfo.RecordCount = q.Count();
			pageInfo.Records = q.Skip((currentPage - 1) * pageSize).Take(pageSize).ToList();
			return pageInfo;
		}
		/// <summary>
		/// 获取文章统计列表
		/// </summary>
		/// <param name="statistics"></param>
		/// <param name="siteId"></param>
		/// <param name="userId"></param>
		/// <param name="startTime"></param>
		/// <param name="endTime"></param>
		/// <param name="keyword"></param>
		/// <returns></returns>
		public static List<ArticleForStatisticsList> GetArticleStatisticsList(int? statistics, int? siteId, Guid? userId, DateTime? startTime, DateTime? endTime, string keyword)
		{
			GenericModuleDataContext dc = new GenericModuleDataContext();
			dc.ObjectTrackingEnabled = false;

			IQueryable<ArticleForStatisticsList> q = ArticleStatisticsQuery(dc, statistics, siteId, userId, startTime, endTime, keyword);

			return q.ToList();
		}

		/// <summary>
		/// 获取管理列表。
		/// </summary>
		/// <param name="articleId">指定文章的标识。</param>
		/// <param name="isEffective">文章是否有效。</param>
		/// <param name="userName">创建用户名。</param>
		/// <param name="startTime">起始时间。</param>
		/// <param name="endTime">结束时间。</param>
		/// <param name="keyword">关键字。</param>
		/// <param name="pageSize">页尺寸。</param>
		/// <param name="currentPage">当前页。</param>
		/// <returns>管理列表。</returns>
		public static PaginationInfo<List<ArticleForManageList>> GetPaginationManageList(int? articleId, bool? isEffective, string userName, DateTime? startTime, DateTime? endTime, string keyword, int pageSize, int currentPage)
		{
			GenericModuleDataContext dc = new GenericModuleDataContext();
			dc.ObjectTrackingEnabled = false;

			var q = from p in dc.Articles
					select p;

			if (articleId.HasValue)
				q = q.Where(p => p.ArticleId == articleId.Value);

			if (isEffective.HasValue)
				q = q.Where(p => p.IsEffective == isEffective.Value);

			if (!string.IsNullOrEmpty(userName))
			{
				Guid? userId = Users.GetUserId(userName);
				if(userId.HasValue)
					q = q.Where(p => p.CreatorId == userId.Value);
				else
					q = q.Where(p => 1 == 0);
			}

			if (startTime.HasValue)
				q = q.Where(p => p.ReleaseDate >= startTime.Value);
			if(endTime.HasValue)
				q = q.Where(p => p.ReleaseDate <= endTime.Value);

			if (!string.IsNullOrEmpty(keyword))
				q = q.Where(p => p.Title.Contains(keyword) || p.ViceTitle.Contains(keyword) || p.Keywords.Contains(keyword) || p.ArtSource.Contains(keyword));

			var q2 = q.Select(p => new ArticleForManageList { 
				ArticleId = p.ArticleId, 
				Title = p.Title, 
				IsEffective = p.IsEffective, 
				ReleaseDate = p.ReleaseDate, 
				CreatorId = p.CreatorId, 
				CreatorName = null 
			}).OrderByDescending(p => p.ReleaseDate);

			PaginationInfo<List<ArticleForManageList>> pageInfo = new PaginationInfo<List<ArticleForManageList>>();
			pageInfo.PageSize = pageSize;
			pageInfo.CurrentPage = currentPage;
			pageInfo.RecordCount = q2.Count();
			pageInfo.Records = q2.Skip((currentPage - 1) * pageSize).Take(pageSize).ToList();
			return pageInfo;
		}

		/// <summary>
		/// 获取选择器列表。
		/// </summary>
		/// <param name="articleId">指定文章的标识。</param>
		/// <param name="keyword">关键字。</param>
		/// <param name="pageSize">页尺寸。</param>
		/// <param name="currentPage">当前页。</param>
		/// <returns>选择器列表。</returns>
		public static PaginationInfo<List<ArticleForManageList>> GetPaginationSelectorList(int? articleId, string keyword, int pageSize, int currentPage)
		{
			GenericModuleDataContext dc = new GenericModuleDataContext();
			dc.ObjectTrackingEnabled = false;

			var q = from p in dc.Articles
					select p;

			if (articleId.HasValue)
				q = q.Where(p => p.ArticleId == articleId.Value);

			if (!string.IsNullOrEmpty(keyword))
				q = q.Where(p => p.Title.Contains(keyword) || p.ViceTitle.Contains(keyword) || p.Keywords.Contains(keyword) || p.ArtSource.Contains(keyword));

			var q2 = q.Select(p => new ArticleForManageList { ArticleId = p.ArticleId, Title = p.Title, IsEffective = p.IsEffective, ReleaseDate = p.ReleaseDate, CreatorId = p.CreatorId });

			PaginationInfo<List<ArticleForManageList>> pageInfo = new PaginationInfo<List<ArticleForManageList>>();
			pageInfo.PageSize = pageSize;
			pageInfo.CurrentPage = currentPage;
			pageInfo.RecordCount = q2.Count();
			pageInfo.Records = q2.Skip((currentPage - 1) * pageSize).Take(pageSize).ToList();
			return pageInfo;
		}
	}







	/// <summary>
	/// Articles 类前台显示部分。
	/// </summary>
	public static partial class Articles
	{
		/// <summary>
		/// 基础列表。
		/// </summary>
		public struct ModuleArticleForClientBaseList
		{
			/// <summary>
			/// 文章所属的站点。
			/// </summary>
			internal int SiteId { get; set; }
			/// <summary>
			/// 文章所属的模块。
			/// </summary>
			public int ModuleId { get; set; }
			/// <summary>
			/// 文章所属的模块代码。
			/// </summary>
			internal string ModuleCode { get; set; }
			/// <summary>
			/// 文章的模块名称。
			/// </summary>
			public string ModuleName { get; set; }
			/// <summary>
			/// 文章的标识。
			/// </summary>
			public int ArticleId { get; set; }
			/// <summary>
			/// 文章的标题。
			/// </summary>
			public string Title { get; set; }
			/// <summary>
			/// 文章的短标题。
			/// </summary>
			public string ShortTitle { get; set; }
			/// <summary>
			/// 文章的中标题。
			/// </summary>
			public string MiddleTitle { get; set; }
			/// <summary>
			/// 文章的题图资源字段。
			/// </summary>
			public string ImageType { get; set; }
			/// <summary>
			/// 文章的代码。
			/// </summary>
			public string ArticleCode { get; set; }
			/// <summary>
			/// 文章的关键字。
			/// </summary>
			public string Keywords { get; set; }
			/// <summary>
			/// 文章的发布时间。
			/// </summary>
			public DateTime ReleaseDate { get; set; }

			public string Summary{get;set;}
			public string ArtContent { get; set; }

			public string ChannelIds { get; set; }
			public bool IsRecommend { get; set; }
			public string RegionIds { get; set; }
		}

		#region 基本列表（指定模块ID）
		/// <summary>
		/// 获取基本列表查询。
		/// </summary>
		/// <param name="dc">数据容器。</param>
		/// <param name="siteId">信息所属的站点。</param>
		/// <param name="moduleId">模块标识。</param>
		/// <param name="keyword">检索的关键字。</param>
		/// <returns>基本列表查询。</returns>
		public static IQueryable<ModuleArticleForClientBaseList> GetBaseListQuery(GenericModuleDataContext dc, int? siteId, int? moduleId, string keyword)
		{
			IQueryable<ModuleArticleForClientBaseList> q;
			if (moduleId == null && siteId.HasValue)
			{
				q = from p in dc.Articles
					from p2 in dc.ModuleArticles
					from p3 in dc.Modules
					where p.ArticleId == p2.ArticleId && p2.ModuleId == p3.ModuleId && p3.SiteId == siteId.Value && p.IsEffective == true && p2.IsEffective == true && p2.ReleaseDate <= DateTime.Now &&p.ReleaseDate <= DateTime.Now
					orderby p2.ArticleOrder descending, p.ReleaseDate descending
					select new ModuleArticleForClientBaseList
					{
						ModuleId = p2.ModuleId,
						ArticleId = p.ArticleId,
						Title = p.Title,
						Keywords = p.Keywords,
						ShortTitle = p.ShortTitle,
						MiddleTitle = p.MiddleTitle,
						ImageType = p.ImageType,
						ArticleCode = p.ArticleCode,
						ReleaseDate = p.ReleaseDate,
						ModuleCode=p3.ModuleCode,
						Summary=p.Summary,
						ArtContent=p.ArtContent,
						ChannelIds=p2.ChannelIds,
						IsRecommend = p2.IsRecommend,
						RegionIds = p2.RegionIds
					};
			}
			else
				q = from p in dc.Articles
					from p2 in dc.ModuleArticles
                    where p.ArticleId == p2.ArticleId && p.IsEffective == true && p2.IsEffective == true && p2.ReleaseDate <= DateTime.Now && p.ReleaseDate <= DateTime.Now
					orderby p2.ArticleOrder descending, p.ReleaseDate descending
					select new ModuleArticleForClientBaseList
					{
						ModuleId = p2.ModuleId,
						ArticleId = p.ArticleId,
						Title = p.Title,
						Keywords = p.Keywords,
						ShortTitle = p.ShortTitle,
						MiddleTitle = p.MiddleTitle,
						ImageType = p.ImageType,
						ArticleCode = p.ArticleCode,
						ReleaseDate = p.ReleaseDate,						
						Summary = p.Summary,
						ArtContent = p.ArtContent,
						ChannelIds = p2.ChannelIds,
						IsRecommend = p2.IsRecommend,
						RegionIds = p2.RegionIds
					};

			if (moduleId.HasValue)
			{
				int[] descendantIds = Modules.GetDescendantIdsByParentId(moduleId.Value);
				if (descendantIds == null || descendantIds.Length == 0)
					q = q.Where(p => p.ModuleId == moduleId.Value);
				else
					q = q.Where(p => descendantIds.Contains(p.ModuleId));
			}

			if (!string.IsNullOrEmpty(keyword))
			{
				string[] keywords = keyword.Split(KeywordSeparator);
				string subQuery = "";
				foreach (var item in keywords)
					subQuery += (string.IsNullOrEmpty(subQuery) ? "" : " || ") + @"Title.Contains(""" + item.Replace("\"", "\\\"") + @""") || Keywords.Contains(""" + item.Replace("\"", "\\\"") + @""")";
				q = q.Where(subQuery);
				//q = q.Where(p => p.Title.Contains(keyword) || p.Keywords.Contains(keyword));
			}

			return q;
		}

		
		/// <summary>
		/// 获取分页基本列表。
		/// </summary>
		/// <param name="siteId">所属站点标识。</param>
		/// <param name="moduleId">模块标识。</param>
		/// <param name="keyword">检索的关键字。</param>
		/// <param name="pageSize">页尺寸。</param>
		/// <param name="currentPage">当前页码。</param>
		/// <returns>分页基本列表。</returns>
		public static PaginationInfo<List<ModuleArticleForClientBaseList>> GetPaginationBaseList(int? siteId, int? moduleId, string keyword, int pageSize, int currentPage)
		{
			GenericModuleDataContext dc = new GenericModuleDataContext();
			dc.ObjectTrackingEnabled = false;

			IQueryable<ModuleArticleForClientBaseList> q = GetBaseListQuery(dc, siteId, moduleId, keyword);

			PaginationInfo<List<ModuleArticleForClientBaseList>> pageInfo = new PaginationInfo<List<ModuleArticleForClientBaseList>>();
			pageInfo.PageSize = pageSize;
			pageInfo.CurrentPage = currentPage;
			pageInfo.RecordCount = q.Count();
			pageInfo.Records = q.Skip((currentPage - 1) * pageSize).Take(pageSize).ToList();
			return pageInfo;
		}

		/// <summary>
		/// 获取基本列表。
		/// </summary>
		/// <param name="siteId">所属站点标识。</param>
		/// <param name="moduleId">模块标识。</param>
		/// <param name="keyword">检索的关键字。</param>
		/// <param name="loadCount">读取的数量。</param>
		/// <returns>基本列表。</returns>
		public static List<ModuleArticleForClientBaseList> GetBaseList(int? siteId, int? moduleId, string keyword, int? loadCount)
		{
			GenericModuleDataContext dc = new GenericModuleDataContext();
			dc.ObjectTrackingEnabled = false;

			IQueryable<ModuleArticleForClientBaseList> q = GetBaseListQuery(dc, siteId, moduleId, keyword);

			if (loadCount.HasValue)
				return q.Take(loadCount.Value).ToList();
			return q.ToList();
		}

		public static int GetCount(int? siteId, int? moduleId, string keyword, DateTime? startTime, DateTime? endTime)
		{
			GenericModuleDataContext dc = new GenericModuleDataContext();
			dc.ObjectTrackingEnabled = false;

			IQueryable<ModuleArticleForClientBaseList> q = GetBaseListQuery(dc, siteId, moduleId, keyword);
			if (startTime.HasValue)
				q = q.Where(p => p.ReleaseDate >= startTime.Value);
			if (endTime.HasValue)
				q = q.Where(p => p.ReleaseDate <= endTime.Value);
			return q.Count();
		}
		#endregion

		#region 基本列表（指定模块代码）
		private static IQueryable<ModuleArticleForClientBaseList> GetBaseListQuery(GenericModuleDataContext dc, int? siteId, string[] moduleCodes, string keyword)
		{
			IQueryable<ModuleArticleForClientBaseList> q;

			q = from p in dc.Articles
				from p2 in dc.ModuleArticles
				from p3 in dc.Modules
                where p.ArticleId == p2.ArticleId && p2.ModuleId == p3.ModuleId && p.IsEffective == true && p2.IsEffective == true && p2.ReleaseDate <= DateTime.Now && p.ReleaseDate <= DateTime.Now
				orderby p2.ArticleOrder descending, p.ReleaseDate descending
				select new ModuleArticleForClientBaseList
				{
					SiteId = p3.SiteId,
					ModuleId = p2.ModuleId,
					ModuleCode = p3.ModuleCode,
					ModuleName = p3.ModuleName,
					ArticleId = p.ArticleId,
					Title = p.Title,
					Keywords = p.Keywords,
					ShortTitle = p.ShortTitle,
					MiddleTitle = p.MiddleTitle,
					ImageType = p.ImageType,
					ArticleCode = p.ArticleCode,
					ReleaseDate = p.ReleaseDate,
					Summary = p.Summary,
					ArtContent = p.ArtContent,
					ChannelIds = p2.ChannelIds,
					IsRecommend = p2.IsRecommend,
					RegionIds = p2.RegionIds
				};

			if (siteId.HasValue)
				q = q.Where(p => p.SiteId == siteId.Value);

			if (moduleCodes != null && moduleCodes.Length > 0)
			{
				q = q.Where(p => moduleCodes.Contains(p.ModuleCode));
			}

			if (!string.IsNullOrEmpty(keyword))
			{
				string[] keywords = keyword.Split(KeywordSeparator);
				string subQuery = "";
				foreach (var item in keywords)
					subQuery += (string.IsNullOrEmpty(subQuery) ? "" : " || ") + @"Title.Contains(""" + item.Replace("\"", "\\\"") + @""") || Keywords.Contains(""" + item.Replace("\"", "\\\"") + @""")";
				q = q.Where(subQuery);
				//q = q.Where(p => p.Title.Contains(keyword) || p.Keywords.Contains(keyword));
			}

			return q;
		}

		public static PaginationInfo<List<ModuleArticleForClientBaseList>> GetPaginationBaseList(int? siteId, string[] moduleCodes, string keyword, int pageSize, int currentPage)
		{
			GenericModuleDataContext dc = new GenericModuleDataContext();
			dc.ObjectTrackingEnabled = false;

			IQueryable<ModuleArticleForClientBaseList> q = GetBaseListQuery(dc, siteId, moduleCodes, keyword);

			PaginationInfo<List<ModuleArticleForClientBaseList>> pageInfo = new PaginationInfo<List<ModuleArticleForClientBaseList>>();
			pageInfo.PageSize = pageSize;
			pageInfo.CurrentPage = currentPage;
			pageInfo.RecordCount = q.Count();
			pageInfo.Records = q.Skip((currentPage - 1) * pageSize).Take(pageSize).ToList();
			return pageInfo;
		}

		public static List<ModuleArticleForClientBaseList> GetBaseList(int? siteId, string[] moduleCodes, string keyword, int? loadCount)
		{
			GenericModuleDataContext dc = new GenericModuleDataContext();
			dc.ObjectTrackingEnabled = false;

			IQueryable<ModuleArticleForClientBaseList> q = GetBaseListQuery(dc, siteId, moduleCodes, keyword);

			if (loadCount.HasValue)
				return q.Take(loadCount.Value).ToList();
			return q.ToList();
		}

		public static int GetCount(int? siteId, string[] moduleCodes, string keyword, DateTime? startTime, DateTime? endTime)
		{
			GenericModuleDataContext dc = new GenericModuleDataContext();
			dc.ObjectTrackingEnabled = false;

			IQueryable<ModuleArticleForClientBaseList> q = GetBaseListQuery(dc, siteId, moduleCodes, keyword);
			if (startTime.HasValue)
				q = q.Where(p => p.ReleaseDate >= startTime.Value);
			if (endTime.HasValue)
				q = q.Where(p => p.ReleaseDate <= endTime.Value);
			return q.Count();
		}
		#endregion



		#region 根据年、月份的查询
		/// <summary>
		/// 根据年份获取文章基础列表
		/// </summary>
		/// <param name="dc"></param>
		/// <param name="siteId"></param>
		/// <param name="moduleId"></param>
		/// <param name="Year"></param>
		/// <param name="keyword"></param>
		/// <returns></returns>
		public static IQueryable<ModuleArticleForClientBaseList> GetBaseListQuery(GenericModuleDataContext dc, int? siteId, int? moduleId,int? Year, string keyword)
		{
			IQueryable<ModuleArticleForClientBaseList> q;
			if (moduleId == null && siteId.HasValue)
			{
				q = from p in dc.Articles
					from p2 in dc.ModuleArticles
					from p3 in dc.Modules
                    where p.ArticleId == p2.ArticleId && p2.ModuleId == p3.ModuleId && p3.SiteId == siteId.Value && p.IsEffective == true && p2.IsEffective == true && p2.ReleaseDate <= DateTime.Now && p.ReleaseDate <= DateTime.Now
					orderby p2.ArticleOrder descending, p.ReleaseDate descending
					select new ModuleArticleForClientBaseList
					{
						ModuleId = p2.ModuleId,
						ArticleId = p.ArticleId,
						Title = p.Title,
						Keywords = p.Keywords,
						ShortTitle = p.ShortTitle,
						MiddleTitle = p.MiddleTitle,
						ImageType = p.ImageType,
						ArticleCode = p.ArticleCode,
						ReleaseDate = p.ReleaseDate,
						ChannelIds = p2.ChannelIds,
						IsRecommend = p2.IsRecommend,
						RegionIds = p2.RegionIds
					};
			}
			else
				q = from p in dc.Articles
					from p2 in dc.ModuleArticles
                    where p.ArticleId == p2.ArticleId && p.IsEffective == true && p2.IsEffective == true && p2.ReleaseDate <= DateTime.Now && p.ReleaseDate <= DateTime.Now
					orderby p2.ArticleOrder descending, p.ReleaseDate descending
					select new ModuleArticleForClientBaseList
					{
						ModuleId = p2.ModuleId,
						ArticleId = p.ArticleId,
						Title = p.Title,
						Keywords = p.Keywords,
						ShortTitle = p.ShortTitle,
						MiddleTitle = p.MiddleTitle,
						ImageType = p.ImageType,
						ArticleCode = p.ArticleCode,
						ReleaseDate = p.ReleaseDate,
						ChannelIds = p2.ChannelIds,
						IsRecommend = p2.IsRecommend,
						RegionIds = p2.RegionIds
					};

			if (moduleId.HasValue)
			{
				int[] descendantIds = Modules.GetDescendantIdsByParentId(moduleId.Value);
				if (descendantIds == null || descendantIds.Length == 0)
					q = q.Where(p => p.ModuleId == moduleId.Value);
				else
					q = q.Where(p => descendantIds.Contains(p.ModuleId));
			}

			if (!string.IsNullOrEmpty(keyword))
			{
				string[] keywords = keyword.Split(KeywordSeparator);
				string subQuery = "";
				foreach (var item in keywords)
					subQuery += (string.IsNullOrEmpty(subQuery) ? "" : " || ") + @"Title.Contains(""" + item.Replace("\"", "\\\"") + @""") || Keywords.Contains(""" + item.Replace("\"", "\\\"") + @""")";
				q = q.Where(subQuery);				
			}

			if (Year.HasValue)
				q = q.Where(p => p.ReleaseDate.Year == Year.Value);

			return q;
		}

		/// <summary>
		/// 根据年份获取文章基础分页列表
		/// </summary>
		/// <param name="siteId"></param>
		/// <param name="moduleId"></param>
		/// <param name="Year"></param>
		/// <param name="keyword"></param>
		/// <param name="pageSize"></param>
		/// <param name="currentPage"></param>
		/// <returns></returns>		
		public static PaginationInfo<List<ModuleArticleForClientBaseList>> GetPaginationBaseList(int? siteId, int? moduleId,int? Year, string keyword, int pageSize, int currentPage)
		{
			GenericModuleDataContext dc = new GenericModuleDataContext();
			dc.ObjectTrackingEnabled = false;

			IQueryable<ModuleArticleForClientBaseList> q = GetBaseListQuery(dc, siteId, moduleId,Year, keyword);

			PaginationInfo<List<ModuleArticleForClientBaseList>> pageInfo = new PaginationInfo<List<ModuleArticleForClientBaseList>>();
			pageInfo.PageSize = pageSize;
			pageInfo.CurrentPage = currentPage;
			pageInfo.RecordCount = q.Count();
			pageInfo.Records = q.Skip((currentPage - 1) * pageSize).Take(pageSize).ToList();
			return pageInfo;
		}

		/// <summary>
		/// 根据年份,月份获取文章基础分页列表
		/// </summary>
		/// <param name="dc"></param>
		/// <param name="siteId"></param>
		/// <param name="moduleId"></param>
		/// <param name="Year"></param>
		/// <param name="Month"></param>
		/// <param name="keyword"></param>
		/// <returns></returns>
		private static IQueryable<ModuleArticleForClientBaseList> GetBaseListQuery(GenericModuleDataContext dc, int? siteId, int? moduleId, int? Year, int? Month, string keyword)
		{
			IQueryable<ModuleArticleForClientBaseList> q;
			if (moduleId == null && siteId.HasValue)
			{
				q = from p in dc.Articles
					from p2 in dc.ModuleArticles
					from p3 in dc.Modules
                    where p.ArticleId == p2.ArticleId && p2.ModuleId == p3.ModuleId && p3.SiteId == siteId.Value && p.IsEffective == true && p2.IsEffective == true && p2.ReleaseDate <= DateTime.Now && p.ReleaseDate <= DateTime.Now
					orderby p.ReadCount, p2.ArticleOrder descending, p.ReleaseDate descending
					select new ModuleArticleForClientBaseList
					{
						ModuleId = p2.ModuleId,
						ArticleId = p.ArticleId,
						Title = p.Title,
						Keywords = p.Keywords,
						ShortTitle = p.ShortTitle,
						MiddleTitle = p.MiddleTitle,
						ImageType = p.ImageType,
						ArticleCode = p.ArticleCode,
						ReleaseDate = p.ReleaseDate,
						ChannelIds = p2.ChannelIds,
						IsRecommend = p2.IsRecommend,
						RegionIds = p2.RegionIds
					};
			}
			else
				q = from p in dc.Articles
					from p2 in dc.ModuleArticles
					where p.ArticleId == p2.ArticleId && p.IsEffective == true && p2.IsEffective == true
					orderby p.ReadCount, p2.ArticleOrder descending, p.ReleaseDate descending
					select new ModuleArticleForClientBaseList
					{
						ModuleId = p2.ModuleId,
						ArticleId = p.ArticleId,
						Title = p.Title,
						Keywords = p.Keywords,
						ShortTitle = p.ShortTitle,
						MiddleTitle = p.MiddleTitle,
						ImageType = p.ImageType,
						ArticleCode = p.ArticleCode,
						ReleaseDate = p.ReleaseDate,
						ChannelIds = p2.ChannelIds,
						IsRecommend = p2.IsRecommend,
						RegionIds = p2.RegionIds
					};

			if (moduleId.HasValue)
			{
				int[] descendantIds = Modules.GetDescendantIdsByParentId(moduleId.Value);
				if (descendantIds == null || descendantIds.Length == 0)
					q = q.Where(p => p.ModuleId == moduleId.Value);
				else
					q = q.Where(p => descendantIds.Contains(p.ModuleId));
			}

			if (!string.IsNullOrEmpty(keyword))
			{
				string[] keywords = keyword.Split(KeywordSeparator);
				string subQuery = "";
				foreach (var item in keywords)
					subQuery += (string.IsNullOrEmpty(subQuery) ? "" : " || ") + @"Title.Contains(""" + item.Replace("\"", "\\\"") + @""") || Keywords.Contains(""" + item.Replace("\"", "\\\"") + @""")";
				q = q.Where(subQuery);
			}

			if (Year.HasValue)
				q = q.Where(p => p.ReleaseDate.Year == Year.Value);

			if (Month.HasValue)
				q = q.Where(p => p.ReleaseDate.Month == Month.Value);

			return q;
		}
		/// <summary>
		/// 根据年份,月份获取文章基础分页列表
		/// </summary>
		/// <param name="siteId"></param>
		/// <param name="moduleId"></param>
		/// <param name="Year"></param>
		/// <param name="Month"></param>
		/// <param name="keyword"></param>
		/// <param name="pageSize"></param>
		/// <param name="currentPage"></param>
		/// <returns></returns>
		public static PaginationInfo<List<ModuleArticleForClientBaseList>> GetPaginationBaseList(int? siteId, int? moduleId, int? Year, int? Month, string keyword, int pageSize, int currentPage)
		{
			GenericModuleDataContext dc = new GenericModuleDataContext();
			dc.ObjectTrackingEnabled = false;

			IQueryable<ModuleArticleForClientBaseList> q = GetBaseListQuery(dc, siteId, moduleId, Year, Month, keyword);

			PaginationInfo<List<ModuleArticleForClientBaseList>> pageInfo = new PaginationInfo<List<ModuleArticleForClientBaseList>>();
			pageInfo.PageSize = pageSize;
			pageInfo.CurrentPage = currentPage;
			pageInfo.RecordCount = q.Count();
			pageInfo.Records = q.Skip((currentPage - 1) * pageSize).Take(pageSize).ToList();
			return pageInfo;
		}
		/// <summary>
		/// 根据年份,月份获取文章基础列表
		/// </summary>
		/// <param name="siteId"></param>
		/// <param name="moduleId"></param>
		/// <param name="Year"></param>
		/// <param name="Month"></param>
		/// <param name="keyword"></param>
		/// <param name="loadCount"></param>
		/// <returns></returns>
		public static List<ModuleArticleForClientBaseList> GetBaseList(int? siteId, int? moduleId, int? Year, int? Month, string keyword,int? loadCount)
		{
			GenericModuleDataContext dc = new GenericModuleDataContext();
			dc.ObjectTrackingEnabled = false;

			IQueryable<ModuleArticleForClientBaseList> q = GetBaseListQuery(dc, siteId, moduleId, Year, Month, keyword);

			if (loadCount.HasValue)
				return q.Take(loadCount.Value).ToList();
			return q.ToList();
		}
		#endregion




		/// <summary>
		/// 关键字分隔符。
		/// </summary>
		public static readonly char[] KeywordSeparator = new char[] { ',', '，', ' ', '　' };

		public struct ModuleArticleForClientSummaryList
		{
			internal int SiteId { get; set; }
			public int ModuleId { get; set; }
			internal string ModuleCode { get; set; }
			public string ModuleName { get; set; }
			public int ArticleId { get; set; }
			public string Title { get; set; }
			public string ShortTitle { get; set; }
			public string MiddleTitle { get; set; }
			public string ImageType { get; set; }
			public string ArticleCode { get; set; }
			public string Summary { get; set; }
			public string Keywords { get; set; }
			public DateTime ReleaseDate { get; set; }
			public string ArtContent { get; set; }
			public string ChannelIds { get; set; }
			public bool IsRecommend { get; set; }
			public string RegionIds { get; set; }

		}

		#region 摘要列表（指定模块ID）
		private static IQueryable<ModuleArticleForClientSummaryList> GetSummaryListQuery(GenericModuleDataContext dc, int? siteId, int? moduleId, string keyword)
		{
			IQueryable<ModuleArticleForClientSummaryList> q;
			if (moduleId == null && siteId.HasValue)
			{
				q = from p in dc.Articles
					from p2 in dc.ModuleArticles
					from p3 in dc.Modules
                    where p.ArticleId == p2.ArticleId && p2.ModuleId == p3.ModuleId && p3.SiteId == siteId.Value && p.IsEffective == true && p2.IsEffective == true && p2.ReleaseDate <= DateTime.Now && p.ReleaseDate <= DateTime.Now
					orderby p2.ArticleOrder descending, p.ReleaseDate descending
					select new ModuleArticleForClientSummaryList
					{
						ModuleId = p2.ModuleId,
						ArticleId = p.ArticleId,
						Title = p.Title,
						Summary = p.Summary,
						Keywords = p.Keywords,
						ShortTitle = p.ShortTitle,
						MiddleTitle = p.MiddleTitle,
						ImageType = p.ImageType,
						ArticleCode = p.ArticleCode,
						ReleaseDate = p.ReleaseDate,
						ArtContent = p.ArtContent,
						ChannelIds = p2.ChannelIds,
						IsRecommend = p2.IsRecommend,
						RegionIds = p2.RegionIds
					};
			}
			else
				q = from p in dc.Articles
					from p2 in dc.ModuleArticles
                    where p.ArticleId == p2.ArticleId && p.IsEffective == true && p2.IsEffective == true && p2.ReleaseDate <= DateTime.Now && p.ReleaseDate <= DateTime.Now
					orderby p2.ArticleOrder descending, p.ReleaseDate descending
					select new ModuleArticleForClientSummaryList
					{
						ModuleId = p2.ModuleId,
						ArticleId = p.ArticleId,
						Title = p.Title,
						Summary = p.Summary,
						Keywords = p.Keywords,
						ShortTitle = p.ShortTitle,
						MiddleTitle = p.MiddleTitle,
						ImageType = p.ImageType,
						ArticleCode = p.ArticleCode,
						ReleaseDate = p.ReleaseDate,
						ArtContent = p.ArtContent,
						ChannelIds = p2.ChannelIds,
						IsRecommend = p2.IsRecommend,
						RegionIds = p2.RegionIds
					};

			if (moduleId.HasValue)
				q = q.Where(p => p.ModuleId == moduleId.Value);

			if (!string.IsNullOrEmpty(keyword))
			{
				string[] keywords = keyword.Split(KeywordSeparator);
				string subQuery = "";
				foreach(var item in keywords)
					subQuery += (string.IsNullOrEmpty(subQuery) ? "" : " || ") + @"Title.Contains(""" + item.Replace("\"", "\\\"") + @""") || Keywords.Contains(""" + item.Replace("\"", "\\\"") + @""")";
				q = q.Where(subQuery);				
			}

			return q;
		}

		public static PaginationInfo<List<ModuleArticleForClientSummaryList>> GetPaginationSummaryList(int? siteId, int? moduleId, string keyword, int pageSize, int currentPage)
		{
			GenericModuleDataContext dc = new GenericModuleDataContext();
			dc.ObjectTrackingEnabled = false;

			IQueryable<ModuleArticleForClientSummaryList> q = GetSummaryListQuery(dc, siteId, moduleId, keyword);

			PaginationInfo<List<ModuleArticleForClientSummaryList>> pageInfo = new PaginationInfo<List<ModuleArticleForClientSummaryList>>();
			pageInfo.PageSize = pageSize;
			pageInfo.CurrentPage = currentPage;
			pageInfo.RecordCount = q.Count();
			pageInfo.Records = q.Skip((currentPage - 1) * pageSize).Take(pageSize).ToList();
			return pageInfo;
		}

		public static List<ModuleArticleForClientSummaryList> GetSummaryList(int? siteId, int? moduleId, string keyword, int? loadCount)
		{
			GenericModuleDataContext dc = new GenericModuleDataContext();
			dc.ObjectTrackingEnabled = false;

			IQueryable<ModuleArticleForClientSummaryList> q = GetSummaryListQuery(dc, siteId, moduleId, keyword);

			if(loadCount.HasValue)
				return q.Take(loadCount.Value).ToList();
			return q.ToList();
		}
		#endregion

		#region 基本列表（指定模块代码）
		private static IQueryable<ModuleArticleForClientSummaryList> GetSummaryListQuery(GenericModuleDataContext dc, int? siteId, string[] moduleCodes, string keyword)
		{
			IQueryable<ModuleArticleForClientSummaryList> q;

			q = from p in dc.Articles
				from p2 in dc.ModuleArticles
				from p3 in dc.Modules
                where p.ArticleId == p2.ArticleId && p2.ModuleId == p3.ModuleId && p.IsEffective == true && p2.IsEffective == true && p2.ReleaseDate <= DateTime.Now && p.ReleaseDate <= DateTime.Now
				orderby p2.ArticleOrder descending, p.ReleaseDate descending
				select new ModuleArticleForClientSummaryList
				{
					SiteId = p3.SiteId,
					ModuleId = p2.ModuleId,
					ModuleCode = p3.ModuleCode,
					ModuleName = p3.ModuleName,
					ArticleId = p.ArticleId,
					Title = p.Title,
					Summary = p.Summary,
					Keywords = p.Keywords,
					ShortTitle = p.ShortTitle,
					MiddleTitle = p.MiddleTitle,
					ImageType = p.ImageType,
					ArticleCode = p.ArticleCode,
					ReleaseDate = p.ReleaseDate,
					ChannelIds = p2.ChannelIds,
					IsRecommend = p2.IsRecommend,
					RegionIds = p2.RegionIds
				};

			if (siteId.HasValue)
				q = q.Where(p => p.SiteId == siteId.Value);

			if (moduleCodes != null && moduleCodes.Length > 0)
			{
				q = q.Where(p => moduleCodes.Contains(p.ModuleCode));
			}

			if (!string.IsNullOrEmpty(keyword))
			{
				string[] keywords = keyword.Split(KeywordSeparator);
				string subQuery = "";
				foreach (var item in keywords)
					subQuery += (string.IsNullOrEmpty(subQuery) ? "" : " || ") + @"Title.Contains(""" + item.Replace("\"", "\\\"") + @""") || Keywords.Contains(""" + item.Replace("\"", "\\\"") + @""")";
				q = q.Where(subQuery);				
			}

			return q;
		}

		public static PaginationInfo<List<ModuleArticleForClientSummaryList>> GetPaginationSummaryList(int? siteId, string[] moduleCodes, string keyword, int pageSize, int currentPage)
		{
			GenericModuleDataContext dc = new GenericModuleDataContext();
			dc.ObjectTrackingEnabled = false;

			IQueryable<ModuleArticleForClientSummaryList> q = GetSummaryListQuery(dc, siteId, moduleCodes, keyword);

			PaginationInfo<List<ModuleArticleForClientSummaryList>> pageInfo = new PaginationInfo<List<ModuleArticleForClientSummaryList>>();
			pageInfo.PageSize = pageSize;
			pageInfo.CurrentPage = currentPage;
			pageInfo.RecordCount = q.Count();
			pageInfo.Records = q.Skip((currentPage - 1) * pageSize).Take(pageSize).ToList();
			return pageInfo;
		}

		public static List<ModuleArticleForClientSummaryList> GetSummaryList(int? siteId, string[] moduleCodes, string keyword, int? loadCount)
		{
			GenericModuleDataContext dc = new GenericModuleDataContext();
			dc.ObjectTrackingEnabled = false;

			IQueryable<ModuleArticleForClientSummaryList> q = GetSummaryListQuery(dc, siteId, moduleCodes, keyword);

			if (loadCount.HasValue)
				return q.Take(loadCount.Value).ToList();
			return q.ToList();
		}
		#endregion
	}
}